﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO; 

using DupeKill.Core.IO; 

namespace DupeKill.Core.Comparison
{
    public class FileSetReader : IDisposable 
    {
        private IFileSystemGateway fileSystem;
        private int chunkSize;
        private Stream[] inputStreams;
        private FileSet fileSet;
        
        private int currentChunk = -1;
        private int currentChunkSize = 0;
        private byte[] buffer; 

        public FileSetReader(IFileSystemGateway fileSystem, FileSet fileSet, int chunkSize)
        {
            if (fileSystem == null)
                throw new ArgumentNullException();
            if (fileSet == null)
                throw new ArgumentNullException();
            if (fileSet.Count < 1)
                throw new ArgumentException(); 
            if (chunkSize < 1)
                throw new ArgumentException();
            this.chunkSize = chunkSize;
            this.fileSystem = fileSystem;
            this.fileSet = fileSet; 
        }

        public int Count
        {
            get
            {
                return fileSet.Count; 
            }
        }

        public bool Read()
        {
            if (currentChunk == -1)
            {
                TryDisposeInputStreams();
                TryCreateBuffer();
                CreateInputStreams();
            }

            for (int i = 0; i < Count; i++)
            {
                currentChunkSize = inputStreams[i].Read(buffer, i * chunkSize, chunkSize);
                if (currentChunkSize == 0)
                    return false; 
            }

            currentChunk++;
            return true; 
        }

        public bool CompareFiles(int x, int y)
        {
            if (currentChunk < 0)
                throw new InvalidOperationException();

            int sx = x * chunkSize;
            int sy = y * chunkSize; 

            for (int i = 0; i < currentChunkSize; i++)
            {
                if (buffer[sx + i] != buffer[sy + i])
                    return false; 
            }

            return true; 
        }

        #region IDisposable Member

        public void Dispose()
        {
            TryDisposeInputStreams(); 
        }

        #endregion

        private void CreateInputStreams()
        {
            TryDisposeInputStreams();
            inputStreams = new Stream[fileSet.Count];

            for (int i = 0; i < fileSet.Count; i++)
            {
                inputStreams[i] = fileSystem.OpenFile(fileSet[i].FullPath);
            }
        }

        private void TryCreateBuffer()
        {
            if (buffer == null)
                buffer = new byte[fileSet.Count * chunkSize];
        }

        private void TryDisposeInputStreams()
        {
            if (inputStreams != null)
            {
                DisposeInputStreams();
            }
        }

        private void DisposeInputStreams()
        {
            for (int i = 0; i < inputStreams.Length; i++)
            {
                inputStreams[i].Dispose();
            }
            inputStreams = null;
        }
    }
}
